﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TransportAbstractionLibrary.Common.BufferPool;
using TransportAbstractionLibrary.Common;
using System.Net.Sockets;

namespace TransportAbstractionLibrary.TCP
{
    public sealed partial class TCPProtocolBase
    {
        SocketEventArgs readingEventArgs;
        object receivingLock;

        private void InitializeRead()
        {
            receivingLock = new object();
            readingEventArgs = bufferManager.CheckOut();
            readingEventArgs.Initialize(this, EventArgsMode.Read);
        }

        private void StartReciving()
        {
            //yay
            Action a = new Action(Receive);
            a.BeginInvoke(null, null);
        }

        private void Receive()
        {
            lock (receivingLock)
            {
                if (!socket.Connected)
                {
                    return;
                }
                try
                {
                    while (!socket.ReceiveAsync(readingEventArgs))
                    {
                        HandleData();
                    }
                }
                catch (SocketException ex)
                {
                    HandleException(ex);
                }
            }
        }

        private void HandleData()
        {
            lock (receivingLock)
            {
                if (readingEventArgs.SocketError == System.Net.Sockets.SocketError.Success && readingEventArgs.BytesTransferred > 0)
                {
                    byte[] data = readingEventArgs.GetRecivedData();
                    upperLayer.Receive(data);
                }
                else
                {
                    HandleException(new TALSocketException(this, "Error while reading data from readingEventArgs", System.Net.Sockets.SocketError.ConnectionAborted));
                }
            }
        }

        void IAsyncHost.OnRecived(SocketEventArgs args)
        {
            if (disposed)
            {
                return;
            }
            if (!socket.Connected)
            {
                Dispose();
                return;
            }
            try
            {
                HandleData();
                Receive();
            }
            catch (SocketException ex)
            {
                HandleException(ex);
            }
        }

        private void DisposeRead()
        {
            try
            {
                bufferManager.CheckIn(readingEventArgs);
                readingEventArgs.Dispose();
                readingEventArgs = null;
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }
            
        }
    }
}
